/**
 * 标准库std中一些常用的工具
 */
use std::{env, str::{from_utf8}, alloc, ptr, rc::{Rc}, cell::{RefCell}};


/**
 * 命令行参数解析 cargo run filename
 */
fn get_args() {
    let args: Vec<String> = env::args().collect();
    println!("命令行参数: {}", args.join(" "));
    // 获取第一个命令行参数（程序名）
    let program_name = args[0].clone();
    println!("program_name:{}", program_name);
    let input_file = match args.get(1) {
        Some(arg) => arg,
        None => {
            println!("请提供一个输入文件名");
            return;
        }
    };
    println!("输入文件: {}", input_file);
}

/**
 * 字符串处理
 */
fn handle_string() {
    let str0 = "测试字符串测试字符串";
    let str1 = String::new(); // 创建一个新的空字符串。
    let mut str2 = String::from(str0); // 从一个&str创建一个新的String，且是可变的字符串。
    str2.push_str("push进来的字符串"); // 将一个&str添加到String的末尾。
    str2.insert_str(0, "插入的数据"); // 边界位置插入一个&str。
    str2.remove(0); // 边界上删除一个字符串
    // str2.clear(); // 清空String
    println!("{},{}", str2, str1);
    let bytes: Vec<u8> = vec![72, 101, 108, 108, 111]; // 字符串编解码
    match from_utf8(&bytes) {
        Ok(e) => println!("{}", e),
        Err(err) => println!("发生错误：{}", err),
    }
    let s = "Hello";
    for c in s.chars() {
        println!("{}", c); // 字符串循环
    }
    println!("查找到的第一个位置：{:?}", str0.find("测试"));
    let replace_str0 = str0.replace("测试", "测试1111"); // 替换字符串不会改变原字符串
    println!("{},{}", str0, replace_str0);
}

/**
 * 内存分配
 * 通过使用Box和Vec等标准库容器来完成的。
 * Box是一个用于在堆上分配内存的通用包装器,Vec则是一个动态数组，它可以在运行时动态地分配和调整内存的大小。
 * Box::new(value): 创建一个新的Box实例，将value封装在其中，并在堆上为其分配内存。
 * Box::into_raw(box): 将一个Box实例转换为其底层指针，以便手动管理内存。需要注意的是，使用此函数需要手动释放内存，否则会导致内存泄漏。
 * Box::from_raw(ptr): 将一个底层指针转换为一个Box实例，以便重新获取对该内存的引用。
 * Vec::new(): 创建一个新的Vec实例，它会根据需要动态地分配内存。
 * Vec::push(item): 向Vec中添加一个元素，并自动调整其大小（如果需要的话）。
 * Vec::pop(): 从Vec中移除最后一个元素，并返回它。
 * Vec::clear(): 清空Vec中的所有元素，并释放其内存。
 */
fn handle_memory() {
    let boxed_value = Box::new(5);
    println!("Value in box: {}", boxed_value);
    // drop(boxed_value); // 释放Box实例所占用的内存
    let raw_ptr = Box::into_raw(boxed_value); // 将其转换为一个原始指针。您可以对原始指针进行低级操作，例如传递给 C 语言库或执行其他特殊操作。
    // 使用裸指针操作内存 
    unsafe {
        let my_struct = &*(raw_ptr as *const i32); // 组合操作符解引用后引用，其中*const i32是一个指向32位整数的裸指针，裸指针是一种低级别的指针类型，可以直接操作内存地址
        println!("Data: {}", my_struct);
    }
    // 还原指针
    unsafe {
        let boxed_value = Box::from_raw(raw_ptr);
        println!("{:?}", boxed_value);
    }
    // 释放内存
    unsafe {
        ptr::drop_in_place(raw_ptr);
    }
}

/** 
 * 错误处理
 * 
 * result
 * Result表示函数执行结果有Err和Ok两种
 * &'static str是一个引用到存储在程序二进制文件中的静态字符串的字面量。这意味着错误消息在编译时就已知，并且不会改变
 * 
 * panic
 * 当一个函数遇到一个无法恢复的错误时，可以使用 panic 来抛出一个异常
 */
fn handle_error() {
    fn handle_error_result() {
        fn divide(a: i32, b: i32) -> Result<i32, &'static str> {
            if b == 0 {
                return Err("除数不能为0");
            } else {
                return Ok(a / b);
            }
        }
        let result = divide(10, 2); // 成功的情况
        match result {
            Ok(num) => println!("结果是：{}", num),
            Err(err) => println!("发生错误：{}", err),
        };
        let result = divide(10, 0); // 失败的情况
        match result {
            Ok(num) => println!("结果是：{}", num),
            Err(err) => println!("发生错误：{}", err),
        };
    }
    fn handle_error_panic() {
        let s = "hello";
        if let Some(i) = s.chars().nth(100) { // 这会panic，因为字符串只有5个字符
            println!("{}", i);
        } else {
            println!("索引越界");
            panic!("panic抛出系统级错误：索引越界");
        }
    }
    handle_error_result();
    handle_error_panic()
}

/**
 * Rc 和 RefCell（内部可变性）是用于处理引用和所有权的重要工具
 * Rc可以用于实现共享所有权，即多个所有者可以同时拥有同一个值的所有权。这对于避免循环引用和内存泄漏非常有用
 * RefCell是一种内部可变性类型，它允许在保留所有权的前提下修改其内部的值。
 * RefCell通过在内部使用一个可变借用（mutable borrow）来实现内部可变性。
 * 当一个RefCell被borrow时，它会创建一个可变借用对象，该对象可以用于修改RefCell内部的值。
 * 当borrow结束时，可变借用对象会被销毁，RefCell的内部值也会被还原为之前的值
 */
#[derive(Debug)] // 主要是针对非字符串例如struct的打印调试用
struct Person {
    name: String,
    age: u32,
}
fn handle_rc() {
    let rc = Rc::new(vec![1, 2, 3]);
    let rc2 = rc.clone();
    println!("{:?}", rc2); // 输出 vec![1, 2, 3]
    println!("{:?}", rc); // 输出 vec![1, 2, 3]

    let person = RefCell::new(Person {
        name: "Alice".to_owned(),
        age: 30,
    });
    println!("{:?}", person.borrow()); // 输出 Person { name: "Alice", age: 30 }
    person.borrow_mut().age = 31; // 修改内部值
    println!("{:?}", person.borrow()); // 输出 Person { name: "Alice", age: 31 }
}

/**
 * rust基础知识
 * 1.所有权（Ownership）：Rust中的内存管理是通过所有权系统进行的。每个值都有其唯一的拥有者，当这个值不再被引用时，内存会被释放。这种系统可以避免许多常见的内存错误。
 * 2.生命周期（Lifetime）：在Rust中，生命周期是用来表示一个引用（reference）的有效期。当引用不再有效时，Rust会将其销毁。
 * 3.借用（Borrowing）：在Rust中，你可以借用一些数据，这意味着你可以在某个时间段内使用它，而不是拥有它。一旦你的作用域结束，你就不能再使用这个数据了。
 * 4.单元测试（Unit Testing）：Rust支持使用#[test]属性来标记函数为单元测试。这些测试在编译时自动运行。
 * 5.属性（Attributes）：Rust中的属性可以用来修改代码的行为。比如，你可以用#[derive(Debug)]属性让一个结构体自动实现Debug trait。
 * 6.闭包（Closures）：闭包在Rust中是一个函数体，它可以捕获其作用域中的变量。闭包可以作为另一个函数的参数或返回值。
 * 7.迭代器（Iterators）：Rust中的迭代器是一个可以产生一系列值的对象。你可以通过.next()方法逐个获取这些值，直到迭代器为空。
 * 8.元组（Tuples）：元组是一种轻量级的数据结构，可以包含不同类型的元素。
 * 9.枚举（Enums）：枚举是一种用户定义的数据类型，它可以包含不同的值和类型。
 * 10.模式匹配（Pattern Matching）：模式匹配是Rust中的一种强大的语法，可以用来进行条件判断和变量绑定。
 * 11.函数调用参数默认值（Default Function Parameters）：Rust允许你在函数定义中为参数设置默认值。当你在调用这个函数时没有提供这个参数的值时，Rust会使用默认值。
 * 12.关联类型（Associated Types）：关联类型是定义在trait中的类型，它们可以让你更简洁地定义和实现复杂的数据结构。
 * 13.引用和借用（References and Borrowing）：在Rust中，你可以创建引用和借用，这样你就可以在不拥有某个值的情况下使用它。这种机制让你可以创建更复杂的数据结构，而不用担心内存管理。
 * 14.所有权转移（Ownership Transfer）：在Rust中，当你把一个值作为函数的返回值或者把它赋值给另一个变量时，这个值的所有权就会发生转移。原来的变量将不再有效。
 * 15.生命周期参数（Lifetime Parameters）：在Rust中，生命周期参数是用来表示引用的有效期的。它们让你能够更精确地控制引用的生命周期。
 * 16.Deref和DerefMut：这两个特性允许你解引用一个引用，直接访问它所引用的对象。
 * 17.特征（Traits）：特征是一种多态机制，它允许你为自定义类型定义行为。你可以为自定义类型实现一个特征接口，这样你就可以像使用其他类型一样使用这个类型。
 * 18.关联特征（Associated Traits）：关联特征是与某个类型关联的特征。它们让你能够更灵活地为自定义类型定义行为。
 * 19.懒加载（Lazy Loading）：在Rust中，你可以使用.lazy()方法来延迟加载一个值，直到你真正需要它为止。
 * 20.接口（Trait Objects）：你可以使用接口来创建一个指向实现了某个接口的对象的长指针。这让你能够编写更灵活的代码。
 * 21.unwrap：unwrap 是 Option 和 Result 类型的一种常见方法，用于从 Option 或 Result 中获取值和未知情况然后通过match或 ? 运算符处理错误。
 */
fn handle_base_concept() {
    // 所有权
    let mut x = 5; // 变量x拥有整数的所有权
    let y = x; // 变量y也拥有了整数的所有权，此时x失去了所有权
    println!("{}, world!", y); // 打印出5

    // 生命周期
    fn print_strings<'a>(slice: &'a Vec<&'a str>) { // '标注生命周期
        for s in slice {
            println!("{}", s);
        }
    }
    let mut strings = vec!["Hello", "World"];
    print_strings(&strings); // 'a 的生命周期与 strings 的生命周期相同，因此可以正常工作
    // 借用
    let mut num1 = 10;
    let num2 = &num1; // 借用num1，创建一个指向num1的引用
    // 单元测试 cargo test
    #[test]
    fn test_rust() {
        print!("text")
    }
    // 属性
    // 闭包
    let x = 10;
    let y = 20;
    let add = |z| x + y + z; // 这是一个闭包，它捕获了x和y变量
    let result = add(5); // 调用闭包，并将结果存储在result变量中
    println!("{}", result);
    // 迭代器
    let mut vec = vec![1, 2, 3, 4, 5]; // 创建一个包含整数的向量
    let mut iter = vec.iter(); // 创建一个迭代器
    while let Some(item) = iter.next() {// 使用迭代器遍历向量中的所有元素
        println!("{}", item); // 打印每个元素
    }
    // 元组
    let tup: (i32, String, u8) = (500, "aaaaa".to_owned(), 1); // 元祖可以看成类数组对象
    println!("{},{},{}", tup.0, tup.1, tup.2);
    // 枚举
    #[derive(Debug)]
    enum Country {
        china,
        USA
    }
    println!("{:?}", Country::USA);
    // 模式匹配
    let number = 10;
    match number {
        0 => println!("Zero"),
        1 | 2 | 3 => println!("One, two or three"),
        _ => println!("Other number"),
    }
    // 引用和借用
    let mut s1 = String::from("hello");
    let s2 = &mut s1; // 创建一个对 s1 的可变引用
    let s3 = &s1; // 创建一个对 s1 的不可变引用
    // 所有权转移
    let mut s4 = String::from("hello");
    let s5 = s4; // 所有权转移
    struct StudentFn {
        name: String,
        age: i32,
        get_name: fn() -> String
    }
    trait Student {
        fn name1() -> String;
    }
    impl Student for StudentFn {
        fn name1() -> String {
            println!("Meow!");
            return "Meow".to_string()
        }
    }
    fn name() -> String {
        return "were".to_string()
    }
    let student = StudentFn {name: "345345345".to_string(), age: 22, get_name: name };
    student.name;
    (student.get_name)();
    StudentFn::name1();
}


fn main() {
    get_args();
    // handle_string();
    handle_memory();
    handle_rc();
    handle_base_concept();
    // handle_error();
}
